package main

import (
	"auth"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"util"

	"github.com/AlexanderChen1989/stack"
	"github.com/AlexanderChen1989/stack/frames/log/gplog"
	"github.com/AlexanderChen1989/stack/frames/requestid"
	"github.com/AlexanderChen1989/stack/frames/router"
	"github.com/AlexanderChen1989/stack/frames/static"
	"github.com/gorilla/mux"
	"github.com/rs/cors"
)

type apiServer struct {
	authStore auth.UserStore
	handler   http.Handler
}

type Point struct {
	X int
	Y int
}

func newServer() *apiServer {
	authStore, err := auth.NewBoltStore("api.db")
	if err != nil {
		panic(err)
	}
	server := &apiServer{
		authStore: authStore,
	}

	server.setup()

	return server
}

func writeJSON(w http.ResponseWriter, content interface{}, err error) {
	w.Header().Set("Content-Type", "application/json")

	type m map[string]interface{}

	payload := m{"status": "success", "content": content}
	if err != nil {
		payload = m{"status": "error", "content": err.Error()}
	}

	if err := json.NewEncoder(w).Encode(payload); err != nil {
		log.Println("writeJSON", err)
	}
}

func (server *apiServer) register(w http.ResponseWriter, r *http.Request) {
	var user auth.User
	json.NewDecoder(r.Body).Decode(&user)
	user, err := server.authStore.CreateUser(user)
	writeJSON(w, user, err)
}

func (server *apiServer) login(w http.ResponseWriter, r *http.Request) {
	var user auth.User
	json.NewDecoder(r.Body).Decode(&user)
	user, err := server.authStore.Authenticate(user)
	writeJSON(w, user, err)
}

func (server *apiServer) generate3DModel(w http.ResponseWriter, r *http.Request) {
	var points []Point
	json.NewDecoder(r.Body).Decode(&points)
	log.Println(points)
	var pointsStr = strconv.Itoa(len(points)) + ";"
	for _, p := range points {
		pointsStr += strconv.Itoa(p.X) + ";" + strconv.Itoa(p.Y) + ";"
	}
	pointsStr = pointsStr[:len(pointsStr)-1]

	var cmd = `C:\DemoExe\DIRTool.exe 0 ` + pointsStr + ` .\static\models\demo.stl`
	log.Println(cmd)

	output, err := util.ExecCmd(`C:\DemoExe\cmd.bat`, cmd)
	log.Println(output)
	log.Println(err)

	writeJSON(w, "", nil)
}

func (server *apiServer) setup() {
	// setup routes
	r := mux.NewRouter()

	r.HandleFunc("/api/register", server.register).Methods(http.MethodPost)
	r.HandleFunc("/api/login", server.login).Methods(http.MethodPost)
	r.HandleFunc("/api/3Dmodel", server.generate3DModel).Methods(http.MethodPost)

	// setup middlewares
	b := stack.NewBuilder()
	b.PushFunc(requestid.New(""))
	b.PushFunc(gplog.New())
	b.PushFunc(gplog.Trace)
	b.PushFunc(static.Static(static.Config{
		From: "static",
		At:   "/",
	}))
	b.PushFunc(router.New(cors.Default().Handler(r)))
	server.handler = b.Build()
}

func (server *apiServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	server.handler.ServeHTTP(w, r)
}
